﻿// Autore: Emanuele Poggi

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.UI;

namespace RecipesManager.Data.Operations
{
    public static class RecipePrinter
    {
        public static string ToHtml(this IRecipe recipe)
        {
            var stringWriter = new StringWriter();
            using (var writer = new HtmlTextWriter(stringWriter))
            {
                writer.WriteLine(GetDocumentStart(recipe.Name));
                RecipePrint(new SubRecipePair {Recipe = recipe, Servings = recipe.Servings}, writer);
                writer.WriteLine(GetDocumentEnd());
            }
            return stringWriter.ToString();
        }

        static IEnumerable<SubRecipePair> StepPrint(IRecipeSteps steps, HtmlTextWriter writer)
        {
            var set = new HashSet<SubRecipePair>();
            if (steps.Count == 0) return set;

            writer.RenderBeginTag("p");
            writer.RenderBeginTag("h2");
            writer.WriteLine("Passi");
            writer.RenderEndTag();

            writer.RenderBeginTag("ol");
            foreach (var s in steps)
            {
                writer.RenderBeginTag("li");
                writer.WriteLine(s.Description);

                if (s.SubRecipe != null)
                    set.Add(new SubRecipePair {Recipe = s.SubRecipe, Servings = s.Servings});
                else if (s.StepHours != null || s.StepMinutes != null || s.Resources.Any())
                {
                    writer.RenderBeginTag("ul");

                    if (s.Resources.Any())
                    {
                        writer.RenderBeginTag("li");
                        writer.WriteLine("<b>Risorse:</b> " + s.Resources);
                        writer.RenderEndTag();
                    }

                    if (s.StepHours != null || s.StepMinutes != null)
                    {
                        writer.RenderBeginTag("li");
                        writer.WriteLine("<b>Tempo di preparazione:</b> ");

                        if (s.StepHours != null)
                            writer.Write(s.StepHours + "h ");

                        if (s.StepMinutes != null)
                            writer.Write(s.StepMinutes + "m");

                        writer.RenderEndTag();
                    }
                    writer.RenderEndTag();
                }
                writer.RenderEndTag();
            }
            writer.RenderEndTag();
            writer.RenderEndTag();
            return set;
        }

        static void RecipePrint(SubRecipePair recipePair, HtmlTextWriter writer)
        {
            var recipe = recipePair.Recipe;
            if (recipe == null)
                throw new ArgumentNullException();

            writer.RenderBeginTag("p");

            if (recipe.PrepHours != null || recipe.PrepMinutes != null)
                writer.Write("<b>Tempo di preparazione: </b>");

            if (recipe.PrepHours != null)
                writer.Write(recipe.PrepHours + "h ");

            if (recipe.PrepMinutes != null)
                writer.Write(recipe.PrepMinutes + "m");

            if (recipe.PrepHours != null || recipe.PrepMinutes != null)
                writer.WriteLine("</br> ");

            if (recipePair.Servings != null)
                writer.WriteLine("<b>Porzioni: </b>" + recipePair.Servings + "</br>");
            else if (recipe.Servings != null)
                writer.WriteLine("<b>Porzioni: </b>" + recipe.Servings + "</br>");

            if (recipe.Source != null)
                writer.WriteLine("<b>Fonte: </b>" + recipe.Source + "</br>");

            writer.Write("<b>Originale: </b>" + (recipe.HasOriginal ? "no" : "si") + "</br>");

            writer.RenderEndTag();

            var factor = 1.0;
            if (recipe.Servings != null && recipePair.Servings != null)
                factor = recipePair.Servings.Value / (double) recipe.Servings;

            IngredientsPrint(recipe.Ingredients, factor, writer);
            var set = StepPrint(recipe.Steps, writer);
            TrialsPrint(recipe.Trials, writer);
            PrintSubRecipes(set, writer, recipe.Name);
        }

        static void TrialsPrint(IRecipeTrials trials, HtmlTextWriter writer)
        {
            if (trials.Count == 0) return;

            writer.RenderBeginTag("p");
            writer.RenderBeginTag("h2");
            writer.WriteLine("Tentativi");
            writer.RenderEndTag();

            writer.RenderBeginTag("ul");
            foreach (var t in trials)
            {
                writer.RenderBeginTag("li");
                writer.Write(t.Notes);
                writer.RenderEndTag();
            }
            writer.RenderEndTag();
            writer.RenderEndTag();
        }

        static void IngredientsPrint(IIngredientQuantities ingredients, double factor, HtmlTextWriter writer)
        {
            if (ingredients.Count == 0) return;

            const string tableHeader =
                "<table style=\"width: 100%; text-align: center; border-collapse: collapse;\" >" +
                "<tr><th>Ingrediente</th><th>Quantità</th><th>Note</th></tr>";
            writer.Write(tableHeader);

            foreach (var i in ingredients)
            {
                writer.RenderBeginTag("tr");
                writer.RenderBeginTag("td");
                writer.WriteLine(i.Name);
                writer.RenderEndTag();
                writer.RenderBeginTag("td");
                var quantity = Math.Round(i.Quantity*factor, 3);
                writer.WriteLine(quantity + " " + i.Measure.Name);
                writer.RenderEndTag();
                writer.RenderBeginTag("td");
                writer.WriteLine(i.Notes);
                writer.RenderEndTag();
                writer.RenderEndTag();
            }
            writer.WriteLine("</table>");
        }

        static void PrintSubRecipes(IEnumerable<SubRecipePair> set, HtmlTextWriter writer, string name)
        {
            foreach (var sr in set)
            {
                writer.WriteLine("<hr size=\"3\" color=\"darkgrey\" width=\"80%\">");
                writer.RenderBeginTag("h1");
                writer.WriteLine(sr.Recipe.Name);
                writer.RenderEndTag();

                writer.RenderBeginTag("h3");
                writer.WriteLine("Sottoricetta di " + name);
                writer.RenderEndTag();

                RecipePrint(sr, writer);
            }
        }

        static string GetDocumentStart(string ricetta)
        {
            return "<html><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>" +
                   "<head><meta charset=\"utf-8\" />" +
                   "<title>" + ricetta + "</title><style>" +
                   "td,th { border: 1px solid black;padding-bottom: .3em; }" +
                   "#titolo, #sottoTitolo , h1 ,h2 ,h3 { text-align: center;font: x-large serif;}" +
                   "h2 { text-align: left; font-size: large ; font-weight:bold;} " +
                   "#sottoTitolo,h3 { font: small serif; margin-bottom: 1em; color: darkgray}" +
                   "#footer { border: 1px solid black;float: right;margin-top: 1em;padding: .5em;}" +
                   "</style></head>" +
                   "<body>" +
                   "<div id=\"titolo\"> " + ricetta + "</div><div id=\"ricetta\">" +
                   "<div id=\"sottoTitolo\">Stampata con Recipe Manager 1.2, HMSoft</div>";
        }

        static string GetDocumentEnd()
        {
            return "</div>" +
                   "</body>" +
                   "</html>";
        }

        struct SubRecipePair
        {
            public IRecipe Recipe;
            public int? Servings;
        }
    }
}